
console.log("---------------------------- t1.js hello ----------------------------")


//document.write("<h1>这是一个标题</h1>")

//alert("我的第一个 JavaScript");

//用分号来结束语句是可选的
var a = 1, b = 2;
c = 3
var c   //如果重新声明 JavaScript 变量，该变量的值不会丢失
console.log("a+b=", a + b + c)
//var ss = null
var ss2
console.log("ss,ss2", 1, ss2)
var ss1 = 123

let names = ["lg", "gt5"]
var names2 = new Array("lg", "gt5")
console.log("names:", names, names[0])
console.log("names2:", names2, names2[1])

var users = { name: "lingg", id: 1211, age: 32 }
users.getName = function () { return this.name }
console.log("users:", users, "name:", users["name"], "nameFunc:", users.getName())

var userObj = new Object()
userObj.name = "lig"
userObj.getName = function () { return this.name }
userObj.show = function () { console.log("my name is:", this.name) }
userObj.id = 1314
console.log("userObj:", userObj, "name:", userObj.getName())

//局部or全部属性
var v1 = 3
var v2 = 21 //全局
//console.log("windows v:", window.v1, window.v2)
console.log("v:", v1, v2)
//delete v1       //无法删除
//delete v2       //可以删除
//console.log("v dd:", v1, v2)

var gv1 = 122
console.log("gv1:", gv1)
function cb() {

    console.log("fun gv1:", gv1)
}
cb()

var str1 = "ase23"
var str2 = new String("t34dyutu7")
console.log(typeof str1)
console.log(typeof str2, str2.length, str2.charAt(0), str2.valueOf())
console.log(`kld o9 "d " '`)
console.log(`str1 = ${str1}`)   //注意 只有`才能对$转义 用"则不会生效

const aaa = 11
{
    const aaa = 12
    console.log("aaa:", aaa)
}

{
    const name = 'John';
    const age = 31;
    const job = 'Web Developer';
    const city = 'Beijing';

    function hello() {
        return 'hello';
    }

    let str = `
    Name:${name}
    age:${age}
    job:${job}
    city:${city}
    calc:${2 + 2}
    function:${hello()}
    sanmu: ${age > 30 ? 'over 30' : 'under 30'}
    `
    console.log(str);
}
console.log((22 > 42) ? "big" : "small")

var cars = ["bsj", "qirui", "audi"]
console.log(">>> cars:", cars.toString())   //
for (let index = 0; index < cars.length; index++) {
    const element = cars[index];
    console.log("car nick:", element)
}
for (var k in cars) {
    console.log("car k:", k)
}
console.log("---------")
cars = { name: "bsj", id: 1233, "age": 32 }
console.log(">>> cars obj:", cars.toString())   //toString 转换为 "[object Object]"
for (k in cars) {
    console.log("car k:", k)
}


lab1:
{
    //for (let index = 0; index < 2; index++) {
    console.log(cars[0]);
    break lab1;
    console.log(cars[1]);
    //} 
}
//对象类型
console.log(typeof undefined, typeof null, typeof cars)
cars = ["bsj", "qirui", "audi"]
console.log(aaa.constructor, cars.constructor, cars.constructor.toString().indexOf("Array"))
console.log(Date(), new Date().getSeconds(), Number(new Date()))

{
    var x = "5"
    var y = +  x    //Operator + 可用于将变量转换为数字
    console.log("y:", y, typeof y)
}

//正则表达式
{
    var patt = /ree/
    //test() 方法用于检测一个字符串是否匹配某个模式，如果字符串中含有匹配的文本，则返回 true，否则返回 false
    var r = patt.test("the best things in life is free!")
    console.log("patt test r:", r)

    console.log(">>>patt.exec:", /free/.exec("the best things in life is free!"))
}



//switch 语句会使用恒等计算符(===)进行比较:
{
    var x = 11;     //作用域都是全局的
    switch (x) {
        case 11: console.log("xxx = 11");
            break;
    }

    //所有的编程语言，包括 JavaScript，对浮点型数据的精确度都很难确定：
    console.log("0.1+0.2=", 0.1 + 0.2)

    //为解决以上问题，可以用整数的乘除法来解决：
    console.log("0.1+0.2=", (0.1 * 10 + 0.2 * 10) / 10)
}
console.log("x=", x)    //在每个代码块中 JavaScript 不会创建一个新的作用域，一般各个代码块的作用域都是全局的。

console.log("this :", typeof this)

var persion = {
    "name": "as",
    "id": 123,
    fullName: function () {
        return this.name + ", " + this.id
        //return this
    }
}
console.log("persion fname:", persion.fullName())

{
    var person1 = {
        fullName: function () {
            return this.fname + "," + this.lname
        }
    }
    var person2 = {
        fname: "aa",
        lname: "bb"
    }


    /* 
        在 JavaScript 中函数也是对象，对象则有方法，apply 和 call 就是函数对象的方法。
        这两个方法异常强大，他们允许切换函数执行的上下文环境（context），即 this 绑定的对象。
        当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法
    */
    console.log("person1.fullName.call:", person1.fullName.call(person2))
}

{
    var x = 22323;      //使用 var 关键字声明的变量不具备块级作用域的特性，它在 {} 外依然能被访问到。
    let xg = 12;        //let 声明的变量只在 let 命令所在的代码块内有效。
}
console.log("xxxx :", x)    //xg    // 这里不能使用 xg 变量

{
    const x = 3;
    //x = 1;
    const cars = { "name": "bsj" }
    cars.name = "gf"
    cars.ss = "d"
    //cars.push("")
    console.log("const cars:", cars)
}

{
    x = "dsd"
    var x

    //xx = 5
    const xx = 1
}


{
    var text = `
        {
            "sites":[
                {"name":"aa1", "id":1001},
                {"name":"aa2", "id":1002}
            ]
        }`
    o = JSON.parse(text)
    console.log("json text", o, o.sites[1])
    console.log("obj 2 json", JSON.stringify(o))
}


{
    setTimeout(function () {
        console.log("time first:", Date())
        setTimeout(function () {
            console.log("time second:", Date())
            setTimeout(function () {
                console.log("time three:", Date())
            }, 2000)
        }, 3000)
    }, 1000)

    console.log("time --------------")
}

{
    //function resolve() {}
    new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log("time 111:", Date())
            resolve()   //resolve() 中可以放置一个参数用于向下一个 then 传递一个值
        }, 1000)
    }).then(function () {
        //如果 then 中返回的是一个 Promise 对象，那么下一个 then 将相当于对这个返回的 Promise 进行操作
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                console.log("time 222:", Date())
                resolve()
            }, 1000)
        })
    }).then(function () {        //then() 可以将参数中的函数添加到当前 Promise 的正常执行序列
        setTimeout(function () {
            console.log("time 333:", Date())
            //resolve()
        }, 1000)
    })
}
/* 
then 方法可以接收两个回调函数作为参数，
第一个回调函数是Promise对象的状态改变为 resoved 是调用，
第二个回调函数是 Promise 对象的状态变为 rejected 时调用。其中第二个参数可以省略。
*/

{
    new Promise(function (resolve1, reject) {
        var a = 0;
        var b = 1;
        if (b == 0) reject("Divide zero");
        else resolve1(a / b);       //resolve1中的参数作为下一个then传递的值
    }).then(function (value) {
        console.log("a / b = " + value);
    }).catch(function (err) {
        console.log(err);
    }).finally(function () {
        console.log("End");
    });
}

{
    function pmPrint(msg, delay) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                console.log("pmPrint:", msg, Date())
            }, delay)
            resolve()
        })
    }
    pmPrint("fr444", 1000).then(function () {    //调用另一个异步任务
        /* return */ pmPrint("gt777", 1000)
    }).then(function () {
        pmPrint("gt888", 1000)
    })

    //异步函数
    async function callPrint() {
        await pmPrint("async 111", 1000)
        await pmPrint("async 222", 1000)
        await pmPrint("async 333", 1000)
    }
    callPrint()

    //如果 Promise 有一个正常的返回值，await 语句也会返回它
    async function callPm2() {
        let pm = await new Promise(function (resolve, reject) {
            resolve("Return value")
        })
        console.log(pm)
    }
    callPm2()
}

{
    new Promise(function (resolve, reject) {
        console.log("----1")
        //resolve(2)
        //return 2
        reject("fldo099")
    }).then(function (v) {
        console.log("----" + v)
        //resolve(2)
        //throw "fff"
        return 3
    }).then(function (v) {
        console.log("----" + v)
        //resolve(4)
    }).catch(function (err) {
        console.log('----err:' + err)
    })
}

{
    var promise = new Promise(function (resolve, reject) {
        //To Do 要异步执行的事情，这个异步执行的事情有可能成功执行完毕，那么Promise将是fulfilled状态，如果执行失败则是rejected;
        //下面测试代码，人为设置为rejected状态;
        reject("将当前构建的Promise对象的状态由pending（进行中）设置为rejected（已拒绝）"); //当然此处也可以设置为fulfilled(已完成)状态
    })

    promise.then(//调用第一个then()
        success => {
            console.log("异步执行成功，状态为：fulfilled，成功后返回的结果是：" + success);
            return (" 当前 success ");
        },
        error => {
            console.log("异步执行失败，状态为rejected，失败后返回的结果是：" + error);
            return (" 当前 error ");
        }
    ).then(
        //调用第二个then() 因为调用第一个then()方法返回的是一个新的promise对象，此对象的状态由上面的success或者error两个回调函数的执行情况决定的：
        //如果回调函数能正常执行完毕，则新的promise对象的状态为fulfilled，下面执行success2,如果回调函数无法正常执行，则promise状态为rejected;下面执行error2
        success2 => {
            console.log("第一个then的回调函数执行成功 成功返回结果：" + success2);
            throw (" 当前 success2 ");//自定义异常抛出
        },
        error2 => {
            console.log("第一个then的回调函数执行失败 失败返回结果：" + error2);
            return (" 当前 error2 ");
        }
    ).catch(err => {
        //当success2或者error2执行报错时，catch会捕获异常;
        console.log("捕获异常：" + err);
    });

    //上述代码,打印如下:
    //异步执行失败，状态为rejected，失败后返回的结果是：将当前构建的Promise对象的状态由pending（进行中）设置为rejected（已拒绝）
    //第一个then的回调函数执行成功 成功返回结果： 当前 error
    //捕获异常： 当前 success2
}

{
    (function () { console.log("nimi func") })()

    //const fx = function(a, b) {return a*b}
    const fx = (a, b) => { return a * b }                    //ES6 新增了箭头函数
    console.log("fx(3,4) = ", fx(3, 4))
}

//函数中改变对象属性
{
    function cg(o) {
        o.age += 1          //改变
        o.fname = "r5"      //扩展
    }
    var o = { "name": "lggg", "age": 32 }
    cg(o)
    console.log("o = ", o)
}

{
    //call() 和 apply() 是预定义的函数方法。 两个方法可用于调用函数，两个方法的第一个参数必须是对象本身
    function myFunction(a, b) {
        return a * b;
    }
    var myObject
    myObject = myFunction.call(myObject, 10, 2);     // 返回 20
    console.log("myObject:", myObject)
}


{
    /* 
    add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。
    这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。
    */
    var add = (function () {
        var counter = 0;
        return function () { return counter += 1; }
    })();

    console.log("add() = ", add())
    console.log("add() = ", add())
    console.log("add() = ", add())
}


function afunc_show(msg) {
    console.log("--------- a.js log:", msg)
}




//导出函数 ES模式   package.json 中 "type": "module",
/*  
export {afunc_show as a_show, cars as acars};      //as 重命名
//export const {cars } = aobj;
//export * from 'a.js';
export {myObject, userObj}

//export default myObject;
export default names ;      //默认导出，所以可以自由使用 import xx 替代 import names

//默认模块无法导出多个
//export default names2 = 'ggtttt'

//nodejs模块的 需要安装插件 node require
//exports.a = 123
*/


//导出函数 NODE模式     package.json 中 "type": "commonjs",
exports.a_show = afunc_show;      //as 重命名
exports.acars = cars;
//export const {cars } = aobj;
//export * from 'a.js';
exports.myObject = myObject;
exports.userObj = userObj;
exports.aa1 = 123;


exports.player = class player {
    constructor(id, name) {
        this.name = name
        this.id = id
    }
    show() {
        console.log(`player info, id:${this.id}, name:${this.name}`)
    }
}

//export default myObject;
exports.names;      //默认导出，所以可以自由使用 import xx 替代 import names


console.log("---------------------------- t1.js 88 ----------------------------")

